package com.mmx.baseservice.admin.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.mmx.baseservice.admin.pojo.AdInfo;
import com.mmx.baseservice.admin.pojo.AdMenu;
import com.mmx.baseservice.admin.pojo.AdRole;
import com.mmx.baseservice.admin.pojo.AdRoleMenu;
import com.mmx.baseservice.admin.service.AdInfoService;
import com.mmx.baseservice.admin.service.AdRoleMenuService;
import com.mmx.baseservice.admin.service.AdRoleService;
import com.mmx.baseservice.admin.tools.enums.AdMenuFlag;
import com.mmx.baseservice.admin.tools.enums.AdRoleStatus;
import com.mmx.baseservice.common.annotation.parameterverify.ParameterVerify;
import com.mmx.baseservice.common.annotation.repeat.PreventRepeat;
import com.mmx.baseservice.common.redis.utils.RedisUtil;
import com.mmx.baseservice.common.utils.CommUtil;
import com.mmx.baseservice.common.utils.page.pojo.PageInfo;
import com.mmx.baseservice.common.utils.page.pojo.PageResult;
import com.mmx.baseservice.common.utils.page.util.PageUtil;
import com.mmx.baseservice.common.utils.returnbody.ResultCodeInfo;
import com.mmx.baseservice.common.utils.returnbody.ReturnBody;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.HandlerMethod;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mmx generator
 * @since 2021-02-03
 */
@Api(tags = "管理员-角色")
@RestController
@RequestMapping("admin/adRole")
public class AdRoleController {

    @Resource
    private HttpServletRequest request;
    @Resource
    private AdRoleService adRoleService;
    @Resource
    private AdRoleMenuService adRoleMenuService;
    @Autowired
    WebApplicationContext applicationContext;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AdInfoService adInfoService;


    @ApiOperation("角色列表")
    @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "status", value = "角色状态")
    @PostMapping("list")
    public String list(PageInfo pageInfo, Integer status) {
        pageInfo.setTimeScreen(AdRole.CREATE_TIME);
        PageResult<AdRole> pageResult = new PageUtil<AdRole>(pageInfo).startPage((page, queryWrapper) -> {
            queryWrapper.eq(AdRole.STATUS, status);
            adRoleService.page(page, queryWrapper);
        });
        return ReturnBody.success(pageResult);
    }


    @ApiOperation("添加角色")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = String.class, name = "roleName", value = "角色名称", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = String.class, name = "remark", value = "备注")
    })
    @PostMapping("add")
    @ParameterVerify(notNull = {"roleName"})
    @PreventRepeat
    public String add(String roleName, String remark) {
        //查重
        AdRole one = adRoleService.getOne(new QueryWrapper<AdRole>().eq(AdRole.ROLE_NAME, roleName));
        if (one != null) {
            return ReturnBody.error("该角色已存在");
        }
        AdRole adRole = new AdRole()
                .setRoleName(roleName)
                .setStatus(AdRoleStatus.NORMAL.getValue())
                .setRemark(remark);
        if (!adRoleService.save(adRole)) {
            return ReturnBody.error();
        }
        return ReturnBody.success();
    }


    @ApiOperation("修改角色")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "id", value = "角色ID", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = String.class, name = "roleName", value = "角色名称", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = String.class, name = "remark", value = "备注")
    })
    @PostMapping("update")
    @ParameterVerify(notNull = {"id", "roleName"})
    public String update(Integer id, String roleName, String remark) {
        if (id == 1) {
            return ReturnBody.error("不可操作超级管理员角色");
        }
        AdRole adRole = new AdRole()
                .setId(id)
                .setRoleName(roleName)
                .setRemark(remark);
        if (!adRoleService.updateById(adRole)) {
            return ReturnBody.error();
        }
        return ReturnBody.success();
    }


    @ApiOperation("冻结或解冻操作")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "id", value = "角色ID", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "status", value = "新状态 -1:冻结; 1:正常", required = true)
    })
    @PostMapping("freezeOrThaw")
    @ParameterVerify(notNull = {"id", "status"})
    public String freezeOrThaw(Integer id, Integer status) {
        if (!status.equals(AdRoleStatus.FREEZE.getValue()) && status.equals(AdRoleStatus.NORMAL.getValue())) {
            return ReturnBody.error(ResultCodeInfo.PARAM_ERROR);
        }
        if (id == 1) {
            return ReturnBody.error("不可操作管理员角色");
        }
        AdRole adRole = new AdRole()
                .setStatus(status)
                .setId(id);
        if (!adRoleService.updateById(adRole)) {
            return ReturnBody.error();
        }
        return ReturnBody.success();
    }


    @ApiOperation("删除角色")
    @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "id", value = "角色ID", required = true)
    @PostMapping("delete")
    @ParameterVerify(notNull = "id")
    public String delete(Integer id) {
        if (id == 1) {
            return ReturnBody.error("不可操作管理员角色");
        }
        return adRoleService.delete(id);
    }


    @ApiOperation("分配菜单")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "roleId", value = "角色ID", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = Integer[].class, name = "menuIds", value = "菜单ID数组", required = true)
    })
    @PostMapping("setRoleMenu")
    @ParameterVerify(notNull = {"roleId"})
    public String setRoleMenu(Integer roleId, Integer[] menuIds) {
        if (menuIds == null) {
            return ReturnBody.error(ResultCodeInfo.PARAM_ERROR);
        }
        if (menuIds.length < 1) {
            return ReturnBody.error("请选择菜单");
        }
        Integer id = (Integer) request.getAttribute(AdInfo.ID);
        if (id != 1) {
            return ReturnBody.error("操作该接口的权限不足");
        }
        return adRoleMenuService.setRoleMenu(roleId, menuIds);
    }

    @ApiOperation("获取该角色拥有的菜单权限")
    @ApiImplicitParam(paramType = "query", dataTypeClass = Integer.class, name = "id", value = "角色ID", required = true)
    @PostMapping("getRoleMenuId")
    public String getRoleMenuId(Integer roleId) {
        if (!CommUtil.checkNull(roleId)) {
            return ReturnBody.error(ResultCodeInfo.PARAM_ERROR);
        }
        AdRoleMenu adminRoleMenu = new AdRoleMenu();
        adminRoleMenu.setRoleId(roleId);
        List<AdMenu> list = adRoleMenuService.selectRoleMenu(adminRoleMenu);
        List<Integer> integers = new ArrayList<>();
        list.stream()
                .filter(item -> item.getFlag().equals(AdMenuFlag.INTERFACE.getValue()))
                .collect(Collectors.toList())
                .forEach(item -> integers.add(item.getId()));
        return ReturnBody.success(integers);
    }

    @ApiOperation("分配接口权限")
    @PostMapping("public/setInterFace")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataTypeClass = Long.class, name = "id", value = "id", required = true),
            @ApiImplicitParam(paramType = "query", dataTypeClass = String.class, name = "interFaceList", value = "可选接口，逗号分隔", required = false),
    })
    public String setInterFace(Long id, String interFaceList) {
        if (!interFaceList.contains("/admin")) {
            return ReturnBody.error("格式错误");
        }
        AdInfo adInfo = adInfoService.getByIdForUpdate(id);
        if (!CommUtil.checkNull(adInfo)) {
            return ReturnBody.error(ResultCodeInfo.SERVICE_EXCEPTION);
        }
        adInfo.setIsDefault(1);
        redisUtil.set(id + "interFaceList", interFaceList);
        if (!adInfoService.updateById(adInfo)) {
            return ReturnBody.error(ResultCodeInfo.SERVICE_EXCEPTION);
        }
        return ReturnBody.success();
    }


    @PostMapping("interFaceList")
    @ApiOperation("接口列表")
    public String getAllUrl() {
        JSONObject interFaceList = ((JSONObject) redisUtil.get("interFaceList"));
        if (CommUtil.checkNull(interFaceList)) {
            return interFaceList.toJSONString();
        }
        List<Map<String, String>> resultList = new ArrayList<>();
        RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        // 获取url与类和方法的对应信息
        Map<RequestMappingInfo, org.springframework.web.method.HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, org.springframework.web.method.HandlerMethod> mappingInfoHandlerMethodEntry : map.entrySet()) {
            Map<String, String> resultMap = new LinkedHashMap<>();
            RequestMappingInfo requestMappingInfo = mappingInfoHandlerMethodEntry.getKey();
            org.springframework.web.method.HandlerMethod handlerMethod = mappingInfoHandlerMethodEntry.getValue();
            resultMap.put("className", handlerMethod.getMethod().getDeclaringClass().getName()); // 类名
            Annotation[] parentAnnotations = handlerMethod.getBeanType().getAnnotations();
            for (Annotation annotation : parentAnnotations) {
                if (annotation instanceof Api) {
                    Api api = (Api) annotation;
                    resultMap.put("classDesc", api.value());
                } else if (annotation instanceof RequestMapping) {
                    RequestMapping requestMapping = (RequestMapping) annotation;
                    if (requestMapping.value().length > 0) {
                        resultMap.put("classURL", requestMapping.value()[0]);//类URL
                    }
                }
            }
            resultMap.put("methodName", handlerMethod.getMethod().getName()); // 方法名
            Annotation[] annotations = handlerMethod.getMethod().getDeclaredAnnotations();
            if (annotations != null) {
                // 处理具体的方法信息
                for (Annotation annotation : annotations) {
                    if (annotation instanceof ApiOperation) {
                        ApiOperation methodDesc = (ApiOperation) annotation;
                        String desc = methodDesc.value();
                        resultMap.put("methodDesc", desc);//接口描述
                    }
                }
            }
            PatternsRequestCondition p = requestMappingInfo.getPatternsCondition();
            for (String url : p.getPatterns()) {
                resultMap.put("methodURL", url);//请求URL
            }
            RequestMethodsRequestCondition methodsCondition = requestMappingInfo.getMethodsCondition();
            for (RequestMethod requestMethod : methodsCondition.getMethods()) {
                resultMap.put("requestType", requestMethod.toString());//请求方式：POST/PUT/GET/DELETE
            }
            resultList.add(resultMap);
        }
        JSONObject object = new JSONObject(true);
        resultList.forEach(item -> {
            String classURL = item.get("methodURL");
            String methodDesc = item.get("methodDesc");
            object.put(classURL, methodDesc);
        });
        //一小时过期
        redisUtil.set("interFaceList", object, 3600);
        return object.toJSONString();
    }
}
